/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
 *
 */
import {expect} from '@jest/globals';
import {iconv} from '@ohos/hvigor';
import * as execa from 'execa';
import fse from 'fs-extra';
import path from 'path';
import {runHvigorAsync} from '../../common/common';
import {resourcesPath} from '../../plugins//common-fun';
import {commonConfig} from '../../plugins/common-config';
import {
  AbilityType,
  APIType,
  APIVersion,
  CaseLevel,
  LanguageType,
  ModuleTemplateType,
  RuntimeOSType,
  SDKType
} from '../../plugins/project-builder/models/constants';
import {TestCaseBuilder} from '../../plugins/task-builder/task-case-builder';
import {ProjectBuildOption, TestCaseFun} from '../../plugins/task-builder/test-case';
import {TestTaskOptionBuilder} from '../../plugins/task-builder/test-task-option';
import {ICaseRecord} from "../../plugins/report-builder/report-models";

const projectBuilderOption: ProjectBuildOption = {
  template: {
    sdk: SDKType.Single,
    runtimeOS: RuntimeOSType.HarmonyOS,
    apiVersion: APIVersion.API10,
    apiType: APIType.STAGE,
    language: LanguageType.ArkTs,
    abilityType: AbilityType.Application,
    entryTemplateType: ModuleTemplateType.NativeC
  }
};

const testfun: TestCaseFun = async (project, taskConfig, record) => {
  const projectRootPath = project.projectRootPath();
  const har1Path = path.resolve(projectRootPath, 'har1');
  const har2Path = path.resolve(projectRootPath, 'har2');
  const har3Path = path.resolve(projectRootPath, 'har3');
  const entryPath = project.getModule('entry').moduleRootPath();
  await fse.copy(path.resolve(resourcesPath, 'module/stage/app/staticLibraryWithC/api11'), har1Path);
  await fse.copy(path.resolve(resourcesPath, 'module/stage/app/staticLibraryWithC/api11'), har2Path);
  await fse.copy(path.resolve(resourcesPath, 'module/stage/app/staticLibraryWithC/api11'), har3Path);
  const moduleFile = await fse.readFile(`${projectRootPath}/build-profile.json5`);
  // 去掉文件中多余的 ,
  const str = iconv.decode(moduleFile, 'utf-8').replace(/(,[\r\n]\s+[}|\]])/g, ($1) => $1.slice(1));
  const moduleObj = JSON.parse(str);
  moduleObj.modules.push(
      {
    name: 'har1',
    srcPath: './har1',
      },
      {
        name: 'har2',
        srcPath: './har2',
      },
      {
        name: 'har3',
        srcPath: './har3',
      }
  );

  await fse.writeFile(`${projectRootPath}/build-profile.json5`, JSON.stringify(moduleObj, null, 2), 'utf-8');
  const har1Main = path.resolve(har1Path, 'src/main');
  const har2Main = path.resolve(har2Path, 'src/main');
  const har3Main = path.resolve(har3Path, 'src/main');
  const entryMain = path.resolve(entryPath, 'src/main');
  await fse.ensureFile(`${har1Main}/module.json5`);
  await fse.writeFile(`${har1Main}/module.json5`, JSON.stringify({
    module: {
      name: 'har1',
      type: 'har',
      deviceTypes: [
        'phone',
        'tablet'
      ]
    }
  }, null, 2), 'utf-8');

  await fse.ensureFile(`${har2Main}/module.json5`);
  await fse.writeFile(`${har2Main}/module.json5`, JSON.stringify({
    module: {
      name: 'har2',
      type: 'har',
      deviceTypes: [
        'phone',
        'tablet'
      ]
    }
  }, null, 2), 'utf-8');

  await fse.ensureFile(`${har3Main}/module.json5`);
  await fse.writeFile(`${har3Main}/module.json5`, JSON.stringify({
    module: {
      name: 'har3',
      type: 'har',
      deviceTypes: [
        'phone',
        'tablet'
      ]
    }
  }, null, 2), 'utf-8');
  // 为新增的har模块修改cpp代码
  changeHarCpp('har1', har1Main);
  changeHarCpp('har2', har2Main);
  changeHarCpp('har3', har3Main);

  // har1进行透传so的配置
  const moduleFileHar = await fse.readFile(`${har1Path}/build-profile.json5`);
  const strHar = iconv.decode(moduleFileHar, 'utf-8').replace(/(,[\r\n]\s+[}|\]])/g, ($1) => $1.slice(1));

  const moduleObjHar = JSON.parse(strHar);
  moduleObjHar.buildOption.nativeLib = {
    librariesInfo: [
      {
        name: "libhar1.so",
        linkLibraries: ["har2::har2", "har3::har3"]
      }
    ]
  };

  await fse.writeFile(`${har1Path}/build-profile.json5`, JSON.stringify(moduleObjHar, null, 2), 'utf-8');
  // 在json5中添加依赖har
  addOhPkgDependencies(entryPath, 'har1', record);
  addOhPkgDependencies(har1Path, 'har2', record);
  addOhPkgDependencies(har2Path, 'har3', record);
  addOhPkgDependencies(har3Path, '', record);

  // 2. sync一下，避免执行clean
  const syncCommand = '--sync -p product=default --analyze=normal --parallel --incremental --no-daemon'.split(' ');
  await runHvigorAsync(project.projectRootPath(), syncCommand);

  // 单独构建har
  const commonCommandHar = '--mode module -p product=default -p module=har1@default assembleHar --analyze=normal --parallel --incremental --no-daemon'.split(' ');
  const resultHar = await runHvigorAsync(project.projectRootPath(), commonCommandHar);
  expect(resultHar.stdout).toContain('BUILD SUCCESSFUL');
  // 解析har包,判断har包中oh-package.json5中是否有透传配置
  const outputDirHar =
      await parse(path.resolve(har1Path, 'build/default/outputs/default/har1.har'));
  const ohPkgHar = await fse.readFile(`${outputDirHar}/package/oh-package.json5`);
  const ohPkgStrHar = iconv.decode(ohPkgHar, 'utf-8').replace(/(,[\r\n]\s+[}|\]])/g, ($1) => $1.slice(1));
  const ohPkgObj = JSON.parse(ohPkgStrHar);
  const linkLibraries = ohPkgObj.nativeComponents[0].linkLibraries;
  expect(linkLibraries.includes("har2::har2") && linkLibraries.includes("har3::har3")).toEqual(true);

  // 执行hap构建
  const commonCommand = '--mode module -p product=default assembleHap --analyze=normal --parallel --incremental --daemon'.split(' ');
  const result = await runHvigorAsync(project.projectRootPath(), commonCommand);
  expect(result.stdout).toContain('BUILD SUCCESSFUL');

  const moduleFileEntry = await fse.readFile(path.resolve(entryPath, '.cxx/default/default/debug/hvigor/arm64-v8a/lib/aarch64-linux-ohos/cmake/har1/har1Config.cmake'));
  const strEntry = iconv.decode(moduleFileEntry, 'utf-8').replace(/(,[\r\n]\s+[}|\]])/g, ($1) => $1.slice(1));
  expect(strEntry.includes('INTERFACE_LINK_LIBRARIES "har2::har2;har3::har3"')).toEqual(true);

}

/**
 * oh-package.json5添加依赖
 */
async function addOhPkgDependencies(modulePath: string, depModuleName: string, record: ICaseRecord) {
  const jsonPath = path.resolve(modulePath, 'oh-package.json5');
  const jsonBuffer = await fse.readFile(jsonPath);
  const jsonData = JSON.parse(iconv.decode(jsonBuffer, 'utf-8').replace('liblibrary.so', `lib${path.basename(modulePath)}.so`));
  jsonData.name = path.basename(modulePath);
  if (depModuleName === '' || depModuleName.length <= 0) {
    await fse.writeFile(jsonPath, JSON.stringify(jsonData,null,2), 'utf-8');
    return;
  }
  jsonData.dependencies[depModuleName] = `file:../${depModuleName}`;
  await fse.writeFile(jsonPath, JSON.stringify(jsonData,null,2), 'utf-8');
  // 执行ohpm install
  const install = await execa.command(commonConfig.ohpmInstallCommand, {
    cwd: modulePath
  });
  record.addStep(`${depModuleName} install`, install);
}

/**
 * har模块内修改cpp代码
 */
async function changeHarCpp(moduleName: string, harMainPath: string) {
  const harOhPkgFile = await fse.readFile(`${harMainPath}/cpp/types/liblibrary/oh-package.json5`);
  const strHar1 = iconv.decode(harOhPkgFile, 'utf-8').replace(/(,[\r\n]\s+[}|\]])/g, ($1) => $1.slice(1));
  const harOhPkgObj = JSON.parse(strHar1);
  harOhPkgObj.name = `lib${moduleName}.so`
  await fse.writeFile(`${harMainPath}/cpp/types/liblibrary/oh-package.json5`, JSON.stringify(harOhPkgObj, null, 2), 'utf-8');
  // 修改cmakeList
  const harCmakeList = await fse.readFile(`${harMainPath}/cpp/CMakeLists.txt`);
  const harCmakeListStr = iconv.decode(harCmakeList, 'utf-8')
      .replace(/(,[\r\n]\s+[}|\]])/g, ($1) => $1.slice(1))
      .replace('library SHARED', `${moduleName} SHARED`)
      .replace('myNpmLib', 'myapplication').replace('library PUBLIC', `${moduleName} PUBLIC`);
  await fse.writeFile(`${harMainPath}/cpp/CMakeLists.txt`, harCmakeListStr, 'utf-8');
}

/**
 * 解析har包
 * @param {string} hqfPath hap包的绝对路径
 * @returns {Promise<string>} 解析的产物目录
 */
async function parse(hqfPath: string) {
  const dir = path.dirname(hqfPath);
  let fileName = path.basename(hqfPath);
  fileName = fileName.replace(fileName.slice(fileName.lastIndexOf('.')), '.tgz');
  const zipPath = path.resolve(dir, fileName);

  // 将生成的xxx包复制为zip包
  fse.copyFileSync(hqfPath, zipPath);
  // 解压zip，解析出生成hap里的内容
  const outputDir = zipPath.slice(0, -9);
  // 通过命令行解压tgz
  await execa.command(`tar zxvf ${zipPath} -C ${outputDir}`);
  return outputDir;
}

TestCaseBuilder.builder()
  .caseName('LIBRARIESINFO_E2E_TEST')
  .description('so的快速链接支持so的依赖配置及透传')
  .projectBuilderOption(projectBuilderOption)
  .taskConfig(TestTaskOptionBuilder.builder().caseLevel(CaseLevel.AR).build())
  .testFun(testfun)
  .load();
